import Portfinder from "portfinder";
import { watch } from "rollup";
import { $ } from "zx";
import electron from "electron";
import { ChildProcess } from "child_process";
import { say } from "cfonts";
import chalk from "chalk";
import { name,version } from "../package.json";
import { AppConfig } from "../config/app.config";
import rollupConfig from "../config/rollup.config";
import { Env } from "../utils/env";
import { App_Env_Enum, App_Modules_Enum, App_NODE_ENV_Enum, Status_Color_Enum } from "../enum/app.enum";
import { resolve } from "path";


Env.setEnv(App_Env_Enum.NODE_ENV,App_NODE_ENV_Enum.DEVELOPMENT)


class DevStarter {

  //端口
  public port: number;

  //electron进程
  public electronProcess: ChildProcess | null = null;

  //手动重启
  public manualRestart: boolean = false;

  //是否已经重启过
  public isRestart = false;

  constructor() {
    this.port = AppConfig.DEV_PORT;
    this.init();
  }


  /**
   * 个性化提示
   */
  public styleLogs(data:any,color:string = Status_Color_Enum.SUCCESS ):void{
    if(data){
      let log = ''
      //转为字符串然后分割换行符
      data = data.toString().split(/\r?\n/);

      if(data?.length > 1){
        data.forEach((val:string)=> {
          val && ( log += val + '\n' )
        })
      }else log = data?.[0]

      console.log(chalk[color].bold(log))
    }
  }

  

  /**
   * 启动vite
   */
  async startVite(): Promise<void> {
    return new Promise((res, rej) => {

      if (this.port) {

        this.styleLogs("启动vite服务器...",Status_Color_Enum.PRIMARY)

        Portfinder.basePort = this.port;
        Portfinder.getPort(async (err, port) => {
          if (err) rej(`Portfinder：${err}`);
          else {
            const { createServer } = await import("vite");

            Env.setEnv(App_Env_Enum.VITE_PORT,String(this.port))

            //在注册vite后再存入env 是不会在vite渲染层中拿到的
            const server = await createServer({
              configFile: resolve("config/vite.config.mts"),
            });
            await server.listen(this.port);

            res();
          }
        });
      } else rej("请配置dev系统端口：config/app.config");
    });
  }

  /**
   * 启动+监听main与preload
   */
  async startMain(): Promise<void> {

    this.styleLogs("编译electron主进程...",Status_Color_Enum.PRIMARY)
    
    return new Promise((res, rej) => {
      const watcher = watch([
        rollupConfig(App_Modules_Enum.MAIN),
        rollupConfig(App_Modules_Enum.PRELOAD),
      ]);
      watcher.on("event", (event) => {
        switch (event.code) {
          case "START":
            if (this.electronProcess) {
              console.time('update')
              this.isRestart = true
              this.styleLogs("重编译electron主进程...",Status_Color_Enum.PRIMARY)
            }
          break;
          case "END":
              
            if (this.electronProcess) {
              this.styleLogs("编译完成，即将重启electron进程...",Status_Color_Enum.PRIMARY)
              this.manualRestart = true;
              this.electronProcess.pid &&
                process.kill(this.electronProcess.pid);
              this.electronProcess = null;
              this.startElectron();
            }else this.styleLogs("编译完成，启动electron进程...",Status_Color_Enum.PRIMARY)

            res();
            break;
          case "ERROR":
            rej(event.error);
            break;
        }
      });
    });
  }

  /**
   * 启动electron
   */
  startElectron(): void {

    let args = ["dist/electron/main/index.js"];
    if (Env.getEnv(App_Env_Enum.NPM_EXECPATH)?.endsWith("yarn.js")) {
      args = args.concat(process.argv.slice(3));
    } else if (Env.getEnv(App_Env_Enum.NPM_EXECPATH)?.endsWith("npm-cli.js")) {
      args = args.concat(process.argv.slice(2));
    }

    this.electronProcess = $.spawn(electron as any, args,{
      stdio: ['pipe', 'pipe', 'pipe', 'ipc'] 
    });

    this.electronProcess.on('message', (message) => {
      if(message === 'ready'){
        this.styleLogs("electron启动成功")
        console.timeEnd(!this.isRestart ? 'dev' : 'update');
        this.manualRestart = false
      }
    });
    
    this.electronProcess.stdout?.on("data", (data) => {
      this.styleLogs("electron进程输出：" + data.toString().trim(),Status_Color_Enum.NORMAL)
    });

    this.electronProcess.stderr?.on("data", (data) => {
      this.manualRestart = false
      this.styleLogs("electron进程报错：" + data.toString().trim(),Status_Color_Enum.ERROR)
    });

    this.electronProcess.on("close", () => {
      //不是手动重启 再退出
     if(!this.manualRestart) process.exit();
    });
      
    this.electronProcess.on("exit", () => {
      console.log('simple-electron退出')
    });
  }

  /**
   * 问候
   */  
  public greeting():void{

    const cols = process.stdout.columns

    cols >= 129 ? say(name, {
      colors: [Status_Color_Enum.PRIMARY],
      font: "simple3d",
      space: false,
    }) :this.styleLogs('welcome ' + name + '_' + version + '\n',Status_Color_Enum.PRIMARY);
  }

  /**
   * 初始化dev
   */
  async init(): Promise<void> {

    this.greeting()

    try {
      console.time('dev');
      await this.startVite();
      await this.startMain();
      this.startElectron();
    } catch (err) {
      this.styleLogs("项目启动失败：" + err, Status_Color_Enum.ERROR)
      process.exit(1);
    }
  }
}

new DevStarter();
